
#define LOG_LVL          LOG_LVL_DEBUG
#define LOG_TAG          "hal_ota"

#include <dohome_type.h>
#include <dohome_error_code.h>
#include <dohome_hal_ota.h>
#include <dohome_log.h>

typedef struct ota_header {
    union {
        struct {
            uint8_t header[16];

            uint8_t type[4];//RAW XZ
            uint32_t len;//body len
            uint8_t pad0[8];

            uint8_t ver_hardware[16];
            uint8_t ver_software[16];

            uint8_t sha256[32];
        } s;
        uint8_t _pad[512];
    } u;
} ota_header_t;

DOHOME_STATIC DOHOME_UINT32_T ota_bin_offset = 0;
DOHOME_STATIC DOHOME_UINT32_T ota_bin_total_len = 0;
// DOHOME_STATIC ota_header_t *g_ota_header;
#define MIN(a, b) ((a) < (b) ? (a) : (b))
DOHOME_STATIC DOHOME_UINT16_T header_offset = 0;
DOHOME_STATIC ota_header_t header_buf;
DOHOME_STATIC int g_use_xz = 0;

DOHOME_STATIC int g_ota_header_found = 0;

DOHOME_STATIC uint8_t g_sha256[32];
DOHOME_STATIC DOHOME_INT_T _check_ota_header(ota_header_t *ota_header, uint32_t *ota_len, int *use_xz)
{
    char str[33];//assume max segment size

    memcpy(str, ota_header->u.s.header, sizeof(ota_header->u.s.header));
    str[sizeof(ota_header->u.s.header)] = '\0';
    DOHOME_LOG_I("[OTA] [HEADER] ota header is = %s", str);

    memcpy(str, ota_header->u.s.type, sizeof(ota_header->u.s.type));
    str[sizeof(ota_header->u.s.type)] = '\0';
    DOHOME_LOG_I("[OTA] [HEADER] file type is = %s", str);

    if (strstr(str, "XZ")) {
        *use_xz = 1;
    } else {
        *use_xz = 0;
    }

    memcpy(ota_len, &(ota_header->u.s.len), 4);
    DOHOME_LOG_I("[OTA] [HEADER] file length (exclude ota header) is %lu", *ota_len);

    memcpy(str, ota_header->u.s.ver_hardware, sizeof(ota_header->u.s.ver_hardware));
    str[sizeof(ota_header->u.s.ver_hardware)] = '\0';
    DOHOME_LOG_I("[OTA] [HEADER] ver_hardware is = %s", str);

    memcpy(str, ota_header->u.s.ver_software, sizeof(ota_header->u.s.ver_software));
    str[sizeof(ota_header->u.s.ver_software)] = '\0';
    DOHOME_LOG_I("[OTA] [HEADER] ver_software is = %s", str);

    memset(g_sha256, 0, sizeof(g_sha256));
    memcpy(g_sha256, ota_header->u.s.sha256, sizeof(ota_header->u.s.sha256));
    DOHOME_LOG_I("[OTA] [HEADER] sha256:");
    // log_buf(g_sha256, sizeof(ota_header->u.s.sha256));

    return 0;
}


DOHOME_UINT8_T dohome_hal_ota_get_schedule(void){

    DOHOME_UINT8_T schedule = 0;
    if(g_ota_header_found){
        schedule = ota_bin_offset*100/(ota_bin_total_len+sizeof(ota_header_t));
    }else{
        schedule = 0;
    }

    DOHOME_LOG_I("ota_get_schedule: %d", schedule);
    return schedule;
}


dohome_op_ret dohome_hal_ota_update(DOHOME_CHAR_T *buf, DOHOME_SIZE_T len){
    DOHOME_STATIC DOHOME_UINT16_T tmp_header_offset = 0;
    if(buf == NULL || len == 0){
        return OPRT_COM_ERROR;
    }
    
    
    return OPRT_OK;
}

dohome_op_ret dohome_hal_ota_end(void){
    DOHOME_STATIC uint8_t sha256[32];
    DOHOME_LOG_I("ota_end");

    
    return OPRT_OK;
}


dohome_op_ret dohome_hal_ota_begin(void){
    int ret;
    uint8_t activeID;
    DOHOME_LOG_I("ota_begin");
    

    return OPRT_OK;
}

